﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MoneyWentWhere.DataModel;
using System.Collections;
using BrightIdeasSoftware;
using System.Windows.Forms;
using MoneyWentWhere.DataModel.Time;

namespace MoneyWentWhere.WinFormsUI.Reports
{
    public class ExpenseReport : ReportType
    {
        ExpenseReportRow _hiddenRoot = null;

        protected override Type RowType
        {
            get { return typeof(ExpenseReportRow); }
        }

        protected override ICollection GetViewObjects(MoneyDataSet dataSet)
        {
            ExpenseReportRow summary = new ExpenseReportRow();
            summary.Text = "Summary";

            var allTx = dataSet.Accounts.SelectMany( x => x.Transactions );

            // TODO: plug in a custom filter
            allTx = allTx.Where(x => x.Kind != TransactionKind.Transfer);


            if (allTx.FirstOrDefault() == null) { return dataSet.Accounts; }

            DateTime start = allTx.Min( x => x.Date );
            DateTime end = allTx.Max( x => x.Date );

            TimePeriod startYear = new TimePeriod(start, TimePeriodUnit.Year);
            foreach (TimePeriod year in startYear.GetPeriodsUntil(end))
            {
                ExpenseReportRow yearRow = new ExpenseReportRow(year);

                TimePeriod startMonth = new TimePeriod(year.Start > start ? year.Start : start, TimePeriodUnit.Month);
                DateTime endMonth = year.End < end ? year.End : end;

                foreach (TimePeriod month in startMonth.GetPeriodsUntil(endMonth))
                {
                    ExpenseReportRow monthRow = new ExpenseReportRow(month);

                    var monthTx = allTx.Where(x => month.Contains(x.Date));
                    monthRow.AddAllNodesAndCalculate(monthTx);
                    yearRow.AddNode(monthRow);
                }
                yearRow.CalculateCells();
                summary.AddNode(yearRow);
            }
            summary.CalculateCells();

            _hiddenRoot = summary;

            // Return nodes, do not show the root
            return summary.Nodes;
        }

        public override void FillView(MoneyDataSet data)
        {
            base.FillView(data);

            TreeListView tree = View as TreeListView;
            if (tree != null && _hiddenRoot != null) 
            {
                var year = _hiddenRoot.Nodes.Last();
                var month = year.Nodes.Last();

                tree.Expand(year);
                tree.Expand(month); 
            }
        }

    }

    class ExpenseReportRow : ReportRow<Transaction>, IComparable
    {
        [OLVColumn(DisplayIndex = 0, FillsFreeSpace = true)]
        public String Text; // derived, first column text

        [OLVColumn(DisplayIndex = 1, Width = 100)]
        public TagSet Tags;

        [OLVColumn(DisplayIndex = 2, Width = 60)]
        public Currency Currency; // derived

        [OLVColumn(DisplayIndex = 3, Width = 100, AspectToStringFormat = "{0:#,0.00}", TextAlign = HorizontalAlignment.Right)] 
        public decimal? Amount;

        public decimal? XR; // derived

        [OLVColumn(DisplayIndex = 4, Width = 100, AspectToStringFormat = "{0:$#,0}", TextAlign = HorizontalAlignment.Right)]         
        public decimal? DcAmount; // derived

        [OLVColumn(DisplayIndex = 5, Width = 100)]
        public Account Account;

        [OLVColumn(DisplayIndex = 6, Width = 50, AspectToStringFormat = "{0:ddd dd}")]
        public DateTime? Date;

        public TransactionKind? Kind;

        public String Comment;

        public ExpenseReportRow() { }

        protected override void CalculateCells(Transaction item)
        {
            if (String.IsNullOrEmpty(item.Comment))
            {
                Text = item.Kind.ToString();
            }
            else 
            {
                Text = item.Comment;
            }

            Account = item.Account;
            Date = item.Date;
            Kind = item.Kind;
            Amount = item.Amount;       
            Tags = item.Tags;
            Comment = item.Comment;

            Currency = item.Account.Currency;

            XR = item.DataSet.GetExchangeRate(
                Currency, 
                Item.DataSet.DefaultCurrency,
                Item.Date.AddSeconds(1));

            DcAmount = item.Amount * XR;
        }

        protected override void CalculateCells(List<ReportRow<Transaction>> nodes)
        {
            IEnumerable<ExpenseReportRow> aNodes = Nodes.Cast<ExpenseReportRow>();

            DcAmount = aNodes.Sum(x => x.DcAmount);
        }

        #region Month delimiter row
        public TimePeriod? Period;

        public ExpenseReportRow(TimePeriod period)
        {
            Period = period;

            switch(period.Unit)
            {
                case TimePeriodUnit.Year:
                    Text = period.Start.ToString("yyyy");
                    break;
                case TimePeriodUnit.Month:
                    Text = period.Start.ToString("MMM yyyy");
                    break;
                default:
                    Text = period.ToString();
                    break;
            }
        }

        // HACK: keeps month delimiter rows in place
        public int CompareTo(object obj)
        {
            ExpenseReportRow that = obj as ExpenseReportRow;
            if (that == null) { return 1; }
            return Comparer.Default.Compare(this.Period, that.Period);
        }

        #endregion
    }

}
